package com.tansun.rule.utils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.jexl2.Expression;
import org.apache.commons.jexl2.JexlContext;
import org.apache.commons.jexl2.JexlEngine;
import org.apache.commons.jexl2.MapContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class CopyOfMathHelper {
	//String[] fbsArr = { "\\", "$", "(", ")", "*", "+", ".", "[", "]", "?", "^", "{", "}", "|" };  
	public static Pattern attrReg = Pattern.compile("#\\{{1}([0-9a-zA-Z]+)\\}");
	public static Pattern indexReg=Pattern.compile("\\(index\\+?[1-9]?\\)$");
	public static Pattern funReg = Pattern.compile("^(trend|mthsncOps|mthsnc|eachrpt|countup|frqpct|sqrt|log|ln|exp|power|year|month|max|min|avg|finarpt|maxdein|ratio|conse2mx|arrsum)\\((.+)\\){1}$");
	private static Logger log = LoggerFactory.getLogger(CopyOfMathHelper.class);
	/**
	 * 
	 * @param attrValue key 属性id  value value 衍生属性所属模型的属性列表
	 * @param mathStr 保存的公式字符串
	 * @return 
	 */
    public static Object invokeMath(HashMap<String,Object> attrValue,String mathStr){
    	if(mathStr==null||"".equals(mathStr)){
    		log.error("输入的数学公式为空");
    		return null;
    	}
    	if(attrValue==null){
    		log.error("输入的模型属性列表为空");
    		return null;
    	}
    	//#{aq7vPlRX}(index)::&gt;::#{aq7vPlRX}(index+2)
    	//conse2mx(1,4,#{8OQWvctv}::+::3,#{aq7vPlRX}(index)::&gt;::#{aq7vPlRX}(index+2))
    	String[] els=mathStr.split("\\]\\[");     	
    	StringBuffer result=new StringBuffer();
    	JexlEngine jexl=new JexlEngine();
    	JexlContext jc = new MapContext();
    	jc.set("jc", jc);
    	jc.set("MathHelper", CopyOfMathHelper.class);
    	jc.set("UserMath", UserMath.class);
    	for(int i=0;i<els.length;i++){
    		String element=els[i].trim();  
    		//操作符处理
    		String e=processOpr(element);
            if(!"notaopr".equals(e)){
            	result.append(e);
            	continue;
            }
    		log.info("元素加工前： "+element);
    		//参数收集 设置属性值
    		Matcher attrM=attrReg.matcher(element);
    		while(attrM.find()){
    			String id=attrM.group(1);    			
    			Object value=attrValue.get(id);
    			if(value==null){
    				log.error("id："+id+" 的参数在输入的模型属性列表中找不到对应属性，模型属性列表：");
    				for(String key:attrValue.keySet()){
    					log.info("id : "+key+" value : "+attrValue.get(key));
    				}
    				return null;
    			}
    		    element=element.replace(attrM.group(), "a"+id);
    			jc.set("a"+id, value);
    		}    
    		log.info("invokeMath替换属性标识操作后 ： "+element);  
    		//替换函数名
    		Matcher funM=funReg.matcher(element);
    		while(funM.find()){
    			element=element.replace(funM.group(1), "MathHelper."+funM.group(1));
    			element=processParam(element,funM.group(2),jc);
    		}
    		Matcher userFunM=UserMath.userFunReg.matcher(element);
    		while(userFunM.find()){
    			element=element.replace(userFunM.group(1), "UserMath."+userFunM.group(1));
    			element=processParam(element,userFunM.group(2),jc);
    		}
    		log.info("invokeMath替换函数名操作后 ： "+element);
    		//处理start end  参数
    		if(element.indexOf(",start,")>0) jc.set("start", "start");
    		if(element.indexOf(",end")>0) jc.set("end", "end");
    		result.append(element);
    	}    	
    	//执行加工后字符串    	
    	log.info("invokeMath表达式 ： "+result);
    	Expression e =jexl.createExpression(result.toString());        	
    	Object o=e.evaluate(jc);
    	log.info("invokeMath计算结果 ： "+o);
    	return o;
    }
    
    public static Object invokeMath(Map<String, Object> dataMap, Map<String, MClass> metaMap,String mathStr){
    	if(mathStr==null||"".equals(mathStr)){
    		log.error("输入的数学公式为空");
    		return null;
    	}    	
    	//#{aq7vPlRX}(index)::&gt;::#{aq7vPlRX}(index+2)
    	//conse2mx(1,4,#{8OQWvctv}::+::3,#{aq7vPlRX}(index)::&gt;::#{aq7vPlRX}(index+2))
    	String[] els=mathStr.split("\\]\\[");     	
    	StringBuffer result=new StringBuffer();
    	JexlEngine jexl=new JexlEngine();
    	JexlContext jc = new MapContext();
    	jc.set("jc", jc);
    	jc.set("MathHelper", CopyOfMathHelper.class);
    	jc.set("UserMath", UserMath.class);
    	for(int i=0;i<els.length;i++){
    		String element=els[i].trim();  
    		//操作符处理
    		String e=processOpr(element);
    		if(!"notaopr".equals(e)){
    			result.append(e);
    			continue;
    		}
    		log.info("元素加工前： "+element);
    		//参数收集 设置属性值
    		Matcher attrM=attrReg.matcher(element);
    		while(attrM.find()){
    			String id=attrM.group(1);    			
    			Object value=getValueById(dataMap, metaMap, id);
    			if(value==null){
    				log.error("id："+id+" 的参数在输入的模型属性列表中找不到对应属性，模型属性列表：");
    				return null;
    			}
    			element=element.replace(attrM.group(), "a"+id);
    			jc.set("a"+id, value);
    		}    
    		log.info("invokeMath替换属性标识操作后 ： "+element);  
    		//替换函数名
    		Matcher funM=funReg.matcher(element);
    		while(funM.find()){
    			element=element.replace(funM.group(1), "MathHelper."+funM.group(1));
    			element=processParam(element,funM.group(2),jc);
    		}
    		Matcher userFunM=UserMath.userFunReg.matcher(element);
    		while(userFunM.find()){
    			element=element.replace(userFunM.group(1), "UserMath."+userFunM.group(1));
    			element=processParam(element,userFunM.group(2),jc);
    		}
    		log.info("invokeMath替换函数名操作后 ： "+element);
    		//处理start end  参数
    		if(element.indexOf(",start,")>0) jc.set("start", "start");
    		if(element.indexOf(",end")>0) jc.set("end", "end");
    		result.append(element);
    	}    	
    	//执行加工后字符串    	
    	log.info("invokeMath表达式 ： "+result);
    	Expression e =jexl.createExpression(result.toString());        	
    	Object o=e.evaluate(jc);
    	log.info("invokeMath计算结果 ： "+o);
    	return o;
    }
    /**
     * by WY
     * 计算表达式赋值
     * @param dataMap 数据Map
     * @param metaMap 元数据Map
     * @param path 数据路径  e.g. Certification.name
     * @param mathStr 计算表达式
     */
    public static void invokeMathToObj(Map<String, Object> dataMap, Map<String, MClass> metaMap, String path,String mathStr){
    	Object obj = invokeMath(dataMap, metaMap, mathStr);
    	RuleHelper ruleHelper = new RuleHelper(metaMap);
    	ruleHelper.setValue(dataMap, path, obj);
    }
    public static Object getValueById(Map<String, Object> dataMap, Map<String, MClass> metaMap,String id){
    	Set<String> set = metaMap.keySet();
    	for (String objType : set) {
			Map<String, MField> fieldMap = metaMap.get(objType).getFieldMap();
			for (String fieldName : fieldMap.keySet()) {
				if(id.equals(fieldMap.get(fieldName).getId())){
					RuleHelper ruleHelper = new RuleHelper(metaMap);
					return ruleHelper.getValue(dataMap, objType+"."+fieldName);
				}
				
			}
		}
    	return null;
    }
    /**
     * 将子公式替换成字符串参数
     * @param element
     * @param paramStr
     * @param jc
     */
    private static String processParam(String element, String paramStr, JexlContext jc) {
    	log.info("函数名参数处理前 ： "+element);
    	String[] param=paramStr.split(",");
    	String res="";
    	for(int i=0;i<param.length;i++){
    		if(param[i].indexOf("::")>0||param[i].indexOf("(index")>=0){
    			int random=(int)(Math.random()*100000);
    			res=res+"param"+random;
    			jc.set("param"+random, param[i]);
    		}else{
    			res=res+param[i];    			
    		}
    		if(i!=(param.length-1)){
    			res=res+",";
    		}else{
    			res=res+",jc";
    		}
    	}    	
    	element=element.replace(paramStr, res);
    	log.info("函数名参数处理后 ： "+element);
    	return element;
	}
	/**
     * 执行子公式
     * @param attrValue
     * @param mathStr
     * @param index
     * @return
     */
    public static Object invokeParam(JexlContext jc,String mathStr,int index){
    	log.info("invokeParam  invokeMath 处理后的子公式： "+mathStr);
    	if(mathStr==null||"".equals(mathStr)){
    		log.error("输入的数学公式为空");
    		return null;
    	}
    	if(jc==null){
    		log.error("输入的JexlContext对象为空");
    		return null;
    	}
    	String[] els=mathStr.split("::");     	
    	StringBuffer result=new StringBuffer();
    	JexlEngine jexl=new JexlEngine();
    	for(int i=0;i<els.length;i++){
    		String element=els[i].trim();  
    		//操作符处理
    		String e=processOpr(element);
            if(!"notaopr".equals(e)){
            	result.append(e);
            	continue;
            }
    		log.info("invokeParam元素加工前： "+element);	
    		//替换函数名
    		Matcher funM=funReg.matcher(element);
    		while(funM.find()){
    			element=element.replace(funM.group(1), "MathHelper."+funM.group(1));
    		}
    		Matcher userFunM=UserMath.userFunReg.matcher(element);
    		while(userFunM.find()){
    			element=element.replace(userFunM.group(1), "UserMath."+userFunM.group(1));
    		}
    		log.info("invokeParam替换函数名操作后 ： "+element);
    		//替换数组的执行格式
    		Matcher indexM=indexReg.matcher(element);
    		while(indexM.find()){
    			element=element.replace(indexM.group(), ".get"+indexM.group());
    		}
    		log.info("invokeParam替换数组的执行格式后： "+element);
    		//处理start end  参数
    		if(element.indexOf(",start,")>0) jc.set("start", "start");
    		if(element.indexOf(",end")>0) jc.set("end", "end");
    		jc.set("index", index);
    		result.append(element);
    	}    	
    	//执行加工后字符串    	
    	log.info("invokeParam表达式 ： "+result);
    	Expression e =jexl.createExpression(result.toString());        	
    	Object o=e.evaluate(jc);
    	log.info("invokeParam计算结果 ： "+o);
    	return o;
    }
    
    private static String processOpr(String element){
		if("&lt;".equals(element)) {
			element="<";
			log.info("单个操作字符不处理 ： "+element);
			return element;
		}
		if("&gt;".equals(element)) {
			element=">";
			log.info("单个操作字符不处理 ： "+element);
			return element;   
		}
		if("OR".equals(element)) {
			element="||";
			log.info("单个操作字符不处理 ： "+element);
			return element;    
		}
		if("AND".equals(element)) {
			element="&&";
			log.info("单个操作字符不处理 ： "+element);
			return element;
		}
		if("=".equals(element)) {
			element="==";
			log.info("单个操作字符不处理 ： "+element);
			return element;
		}
		if(element.length()==1) {
			log.info("单个操作字符不处理 ： "+element);
			return element;
		}
    	return "notaopr";
    }
    /**
     * 幂
     * @param a
     * @param b
     * @param jc
     * @return
     */
    public static Object power(Object a, Object b ,JexlContext jc){
    	double aa;
    	double bb;
    	try{
    		aa=Double.parseDouble(a.toString());  
   		}catch(NumberFormatException e){
   			aa=Double.parseDouble(invokeParam(jc,a.toString(),0).toString());
   		}   
    	try{
    		bb=Double.parseDouble(b.toString());  
   		}catch(NumberFormatException e){
   			bb=Double.parseDouble(invokeParam(jc,b.toString(),0).toString());
   		}  
    	return new BigDecimal( Math.pow(aa, bb)).setScale(UserMath.scale, BigDecimal.ROUND_HALF_UP).doubleValue();
    }
    /**
     * 开方
     * @param a
     * @param jc
     * @return
     */
    public static Object sqrt(Object a,JexlContext jc){
    	double res;
    	try{
    		res=Double.parseDouble(a.toString());  
   		}catch(NumberFormatException e){
   			res=Double.parseDouble(invokeParam(jc,a.toString(),0).toString());
   		}   
    	return new BigDecimal(Math.sqrt(res)).setScale(UserMath.scale, BigDecimal.ROUND_HALF_UP).doubleValue();
    }
  /**  
   * 以e为底
   * @param a
   * @return
   */
    public static Object ln(Object a,JexlContext jc){
    	double res;
    	try{
    		res=Double.parseDouble(a.toString());  
   		}catch(NumberFormatException e){
   			res=Double.parseDouble(invokeParam(jc,a.toString(),0).toString());
   		}   
    	return new BigDecimal(Math.log(res)).setScale(UserMath.scale, BigDecimal.ROUND_HALF_UP).doubleValue();
    }
    /**
     * 
     * @param a
     * @param jc
     * @return
     */
    public static Object exp(Object a,JexlContext jc){
    	double res;
    	try{
    		res=Double.parseDouble(a.toString());  
   		}catch(NumberFormatException e){
   			res=Double.parseDouble(invokeParam(jc,a.toString(),0).toString());
   		}   
    	return new BigDecimal(Math.exp(res)).setScale(UserMath.scale, BigDecimal.ROUND_HALF_UP).doubleValue();
    }
    /**
     * b为底数
     * @param a
     * @param b
     * @return
     */
    public static Object log(Object a,Object b,JexlContext jc){
    	double aa;
    	double bb;
    	try{
    		aa=Double.parseDouble(a.toString());  
   		}catch(NumberFormatException e){
   			aa=Double.parseDouble(invokeParam(jc,a.toString(),0).toString());
   		}   
    	try{
    		bb=Double.parseDouble(b.toString());  
   		}catch(NumberFormatException e){
   			bb=Double.parseDouble(invokeParam(jc,b.toString(),0).toString());
   		}  
    	BigDecimal aaa=new BigDecimal( Math.log(aa));
    	BigDecimal bbb=new BigDecimal(Math.log(bb));
    	return  aaa.divide(bbb,UserMath.scale, BigDecimal.ROUND_HALF_UP).doubleValue();
    }
   
    /**
     * 目标日期至今的年数    
     * @param d
     * @return
     */
    public static Object year(Date d,JexlContext jc){
	   Calendar now=Calendar.getInstance();
	   now.setTime(new Date());
	   Calendar target=Calendar.getInstance();
	   target.setTime(d);
	   int nowYear=now.get(Calendar.YEAR);
	   int targetYear=target.get(Calendar.YEAR);
	   now.set(Calendar.YEAR, targetYear);
	   if(now.before(target)){
		   return nowYear-targetYear-1;
	   }
    	return nowYear-targetYear;
    }
    /**
     * 目标日期至今的月份数 
     * @param d
     * @return
     */
    public static Object month(Date d,JexlContext jc){
    	Integer year=(Integer) CopyOfMathHelper.year(d,jc);
    	Calendar now=Calendar.getInstance();
  	   now.setTime(new Date());
  	   Calendar target=Calendar.getInstance();
  	   target.setTime(d);
  	   int nowMon=now.get(Calendar.MONTH);
  	   int targetMon=target.get(Calendar.MONTH);
  	   int nowDate=now.get(Calendar.DAY_OF_MONTH);
  	   int targetDate=target.get(Calendar.DAY_OF_MONTH);  	  
  	   if(nowMon==targetMon&&nowDate>=targetDate){
  		   return year*12;
  	   }else if(nowMon>targetMon&&nowDate<targetDate){
  		   return year*12+(nowMon-targetMon-1);
  	   }else if(nowMon>targetMon&&nowDate>=targetDate){
  		 return year*12+(nowMon-targetMon);
  	   }else if(nowMon<targetMon&&nowDate<targetDate){
  		 return year*12+(Calendar.DECEMBER-targetMon+nowMon);
  	   }else if(nowMon<targetMon&&nowDate>=targetDate){
  		 return year*12+(Calendar.DECEMBER-targetMon+nowMon+1);
  	   }else if(nowMon==targetMon){
  		   return year*12+Calendar.DECEMBER;
  	   }
  	   return 0;
    }
    /**
     * 最大值
     * @param list
     * @param start
     * @param end
     */
    public static Object max(Object start,Object end,List list,Integer tob,JexlContext jc){
    	int startIndex=0;
    	int endIndex=list.size()-1;
    	if(!"start".equals(start)){    		
    		int a=Integer.parseInt(start.toString())-1;
    		if(0<=a&&a<=endIndex){
    			startIndex=a;
    		}
    	}
    	if(!"end".equals(end)){
    		int b=Integer.parseInt(end.toString())-1;
    		if(0<=b&&b<=endIndex){
    			endIndex=b;
    		}    		
    	} 
    	tob=tob-1;
    	if(endIndex>tob&&tob>=0) endIndex=tob;
    	//下标处理结束
    	double max=Double.parseDouble(list.get(startIndex).toString());
    	if(startIndex==endIndex) return max;
    	for(int i=(startIndex+1);i<=endIndex;i++){
    		if(Double.parseDouble(list.get(i).toString())>max){
    			max=Double.parseDouble(list.get(i).toString());
    		}
    	}    	
    	BigDecimal   b=new BigDecimal(max);
    	return b.setScale(UserMath.scale, BigDecimal.ROUND_HALF_UP).doubleValue();
    }
    /**
     * 最小值
     * @param list
     * @param start
     * @param end
     */
    public static Object min(Object start,Object end,List list,Integer tob,JexlContext jc){
    	int startIndex=0;
    	int endIndex=list.size()-1;
    	if(!"start".equals(start)){    		
    		int a=Integer.parseInt(start.toString())-1;
    		if(0<=a&&a<=endIndex){
    			startIndex=a;
    		}
    	}
    	if(!"end".equals(end)){
    		int b=Integer.parseInt(end.toString())-1;
    		if(0<=b&&b<=endIndex){
    			endIndex=b;
    		}    		
    	} 
    	tob=tob-1;
    	if(endIndex>tob&&tob>=0) endIndex=tob;
    	//下标处理结束
    	double min=Double.parseDouble(list.get(startIndex).toString());
    	if(startIndex==endIndex) return min;
    	for(int i=(startIndex+1);i<=endIndex;i++){
    		if(Double.parseDouble(list.get(i).toString())<min){
    			min=Double.parseDouble(list.get(i).toString());
    		}
    	}    	
    	BigDecimal   b=new BigDecimal(min);
    	return b.setScale(UserMath.scale, BigDecimal.ROUND_HALF_UP).doubleValue();
    }
    /**
     * 平均值
     * @param list
     * @param start
     * @param end
     */
    public static Object avg(Object start,Object end,List list,Integer tob,JexlContext jc){
    	int startIndex=0;
    	int endIndex=list.size()-1;
    	if(!"start".equals(start)){    		
    		int a=Integer.parseInt(start.toString())-1;
    		if(0<=a&&a<=endIndex){
    			startIndex=a;
    		}
    	}
    	if(!"end".equals(end)){
    		int b=Integer.parseInt(end.toString())-1;
    		if(0<=b&&b<=endIndex){
    			endIndex=b;
    		}    		
    	} 
    	tob=tob-1;
    	if(endIndex>tob&&tob>=0) endIndex=tob;
    	//下标处理结束
    	double sum=Double.parseDouble(list.get(startIndex).toString());
    	int amount=endIndex-startIndex+1;
    	for(int i=(startIndex+1);i<=endIndex;i++){
    		sum=sum+Double.parseDouble(list.get(i).toString());    		
    	}     	
    	BigDecimal   b=new BigDecimal(sum/amount);
    	return b.setScale(UserMath.scale, BigDecimal.ROUND_HALF_UP).doubleValue();
    }
    /**
     * 最大连续
     * @param start
     * @param end
     * @param tobStr
     * @param condition
     * @param jc
     * @return
     */
    public static Object conse2mx(Object start,Object end,Object tobStr,String condition,JexlContext jc){
    	int startIndex=0;
    	int endIndex=0;    	
    	if(!"start".equals(start.toString())){    		
    		startIndex=Integer.parseInt(start.toString())-1;    			
    	}
    	
    	if(!"end".equals(end.toString())){
    		endIndex=Integer.parseInt(end.toString())-1;    		   		
    	}     	
    	int tob;    
       	try{
       		    tob=Integer.parseInt(tobStr.toString())-1;  
    		}catch(NumberFormatException e){
    			tob=(Integer) invokeParam(jc,tobStr.toString(),0)-1;
    	}   
    	if(endIndex>tob&&tob>=0) endIndex=tob;
    	//下标处理结束
    	int leftIndex=startIndex-1;
    	int rightIndex=startIndex-1;  
    	int result=0;
    	log.info("endIndex ： "+endIndex);
    	for(int i=startIndex;i<=endIndex;i++){
    		Object o=invokeParam(jc,condition,i);
    		if("true".equals(o.toString())){
    			rightIndex=i;
    		}
    		if("false".equals(o.toString())||i==endIndex){
    			if(result<(rightIndex-leftIndex)) result=rightIndex-leftIndex;
    			rightIndex=i;
    			leftIndex=i;
    		}
    	}
    	log.info("conse2mx 的计算结果 ： "+result);
    	return  result;
    }
    /**
     * 数组和
     * @param start
     * @param end
     * @param list
     * @param jc
     * @return
     */
    public static Object arrsum(Object start,Object end,List list,JexlContext jc){
    	int startIndex=0;
    	int endIndex=list.size()-1;
    	if(!"start".equals(start)){    		
    		int a=Integer.parseInt(start.toString())-1;
    		if(0<=a&&a<=endIndex){
    			startIndex=a;
    		}
    	}
    	if(!"end".equals(end)){
    		int b=Integer.parseInt(end.toString())-1;
    		if(0<=b&&b<=endIndex){
    			endIndex=b;
    		}    		
    	} 
    	//下标处理结束
    	double sum=Double.parseDouble(list.get(startIndex).toString());
    	for(int i=(startIndex+1);i<=endIndex;i++){
    		sum=sum+Double.parseDouble(list.get(i).toString());    		
    	}  
    	BigDecimal   b=new BigDecimal(sum);
    	return b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
    }
    /**
     * 最大不同  同一个数组两个值差值最大
     * @param start 
     * @param end
     * @param list1
     * @param list2
     * @param tob
     * @return
     */
    public static Object maxdein(Object start,Object end,String ele1,String ele2,Integer tob,JexlContext jc){
    	int startIndex=0;
    	int endIndex=0;    	
    	if(!"start".equals(start.toString())){    		
    		startIndex=Integer.parseInt(start.toString())-1;    			
    	}
    	
    	if(!"end".equals(end.toString())){
    		endIndex=Integer.parseInt(end.toString())-2;    		   		
    	}     	
    	tob=tob-2;    	
    	if(endIndex>tob&&tob>=0) endIndex=tob;
    	//下标处理结束
    	double result=0;
    	for(int i=startIndex;i<=endIndex;i++){
    		String condition=ele1+"::>::"+ele2;
    		Object o=invokeParam(jc,condition,i);
    		if("true".equals(o.toString())){
    			String condition2=ele1+"::-::"+ele2;
    		    double o2=Double.parseDouble(invokeParam(jc,condition2,i).toString());
    			if(result<o2){
    				result=o2;
    			}
    		}
    	}
    	return result;
    }
    /**
     * 两个数组和的比值 百分比
     * @param start
     * @param end
     * @param arr1
     * @param arr2
     * @param tob
     * @param jc
     * @return
     */
    public static Object finarpt(Object start,Object end,List arr1,List arr2,Integer tob,JexlContext jc){
    	int startIndex=0;
    	int endIndex=0;    	
    	if(!"start".equals(start.toString())){    		
    		startIndex=Integer.parseInt(start.toString())-1;    			
    	}
    	
    	if(!"end".equals(end.toString())){
    		endIndex=Integer.parseInt(end.toString())-1;    		   		
    	}     	
    	tob=tob-1;    	
    	if(endIndex>tob&&tob>=0) endIndex=tob;
    	//下标处理结束
    	BigDecimal num=new BigDecimal(0);
    	BigDecimal den=new BigDecimal(0);
    	for(int i=startIndex;i<=endIndex;i++){
    		BigDecimal n=new BigDecimal(Double.parseDouble(arr1.get(i).toString()));
    		BigDecimal d=new BigDecimal(Double.parseDouble(arr2.get(i).toString()));
    		num=num.add(n).setScale(2, BigDecimal.ROUND_HALF_UP);
    		den=den.add(d).setScale(2, BigDecimal.ROUND_HALF_UP);
    	}
    	if(den.doubleValue()<=0) return -999999;
    	num=new BigDecimal(num.doubleValue()*100);
    	return num.divide(den, UserMath.scale, BigDecimal.ROUND_HALF_UP).doubleValue();
    }
    /**
     * 百分比
     * @param a
     * @param b
     * @param jc
     * @return
     */
    public static Object ratio(double a,double b,JexlContext jc){
    	if(b<=0) return -999999;
    	BigDecimal num=new BigDecimal(a*100);
    	BigDecimal den=new BigDecimal(b);    	
    	return num.divide(den, UserMath.scale, BigDecimal.ROUND_HALF_UP).doubleValue();
    }
    /**
     * 频率比例
     * @param start
     * @param end
     * @param tob
     * @param denCondition
     * @param numCondition
     * @param denval
     * @param numval
     * @param jc
     * @return
     */
    public static Object frqpct(Object start,Object end,Object tobStr,String denCondition,String numCondition,double denval,double numval,JexlContext jc){
    	int startIndex=0;
    	int endIndex=0;    	
    	if(!"start".equals(start.toString())){    		
    		startIndex=Integer.parseInt(start.toString())-1;    			
    	}
    	
    	if(!"end".equals(end.toString())){
    		endIndex=Integer.parseInt(end.toString())-1;    		   		
    	}     	
    	int tob;    
       	try{
       		    tob=Integer.parseInt(tobStr.toString())-1;  
    		}catch(NumberFormatException e){
    			tob=(Integer) invokeParam(jc,tobStr.toString(),0)-1;
    	}    	
    	if(endIndex>tob&&tob>=0) endIndex=tob;
    	//下标处理结束
    	double den=0;
    	double num=0;
    	for(int i=startIndex;i<=endIndex;i++){
    		if("true".equals(invokeParam(jc,denCondition,i).toString())){
    			den=den+denval;
    		}
    		if("true".equals(invokeParam(jc,numCondition,i).toString())){
    			num=num+numval;
    		}
    	}
    	if(den<=0) return -999999;
    	BigDecimal a=new BigDecimal(num*100);
    	BigDecimal b=new BigDecimal(den);
    	return   a.divide(b, UserMath.scale, BigDecimal.ROUND_HALF_UP).doubleValue();
    }
    /**
     * 计数
     * @param start
     * @param end
     * @param tobStr
     * @param condition
     * @param jc
     * @return
     */
    public static Object countup(Object start,Object end,Object tobStr,String condition,JexlContext jc){
    	int startIndex=0;
    	int endIndex=0;    	
    	if(!"start".equals(start.toString())){    		
    		startIndex=Integer.parseInt(start.toString())-1;    			
    	}
    	
    	if(!"end".equals(end.toString())){
    		endIndex=Integer.parseInt(end.toString())-1;    		   		
    	}     	
    	int tob;    
       	try{
       		    tob=Integer.parseInt(tobStr.toString())-1;  
    		}catch(NumberFormatException e){
    			tob=(Integer) invokeParam(jc,tobStr.toString(),0)-1;
    	}   
    	if(endIndex>tob&&tob>=0) endIndex=tob;
    	//下标处理结束
    	int count=0;
    	for(int i=startIndex;i<=endIndex;i++){
    		if("true".equals(invokeParam(jc,condition,i).toString())){
    			count++;
    		}    		
    	}
    	return count;
    }
    /**
     * 笔均
     * @param start
     * @param end
     * @param tob
     * @param numList
     * @param denList
     * @param limitList
     * @param jc
     * @return
     */
    public static Object eachrpt(Object start,Object end,Integer tob,List numList,List denList,List limitList,JexlContext jc){
    	int startIndex=0;
    	int endIndex=0;    	
    	if(!"start".equals(start.toString())){    		
    		startIndex=Integer.parseInt(start.toString())-1;    			
    	}    	
    	if(!"end".equals(end.toString())){
    		endIndex=Integer.parseInt(end.toString())-1;    		   		
    	}     	
    	tob=tob-1;    	
    	if(endIndex>tob&&tob>=0) endIndex=tob;
    	//下标处理结束
    	BigDecimal num=new BigDecimal(0);
    	BigDecimal den=new BigDecimal(0);
    	for(int i=startIndex;i<=endIndex;i++){
    		BigDecimal d=new BigDecimal(denList.get(i).toString());
    		BigDecimal n=new BigDecimal(numList.get(i).toString());  
    		BigDecimal l=new BigDecimal(limitList.get(i).toString());
    		if(d.intValue()>0){
    			num=num.add(n.divide(d,UserMath.scale, BigDecimal.ROUND_HALF_UP));
    			den=den.add(l);
    		}
    	}
    	if(den.doubleValue()==0) return -999999;
    	return new BigDecimal(num.doubleValue()*100).divide(den,UserMath.scale, BigDecimal.ROUND_HALF_UP).doubleValue();
    }
    /**
     * 满足条件最小月份
     * @param start
     * @param end
     * @param index
     * @param tobStr
     * @param condition
     * @param jc
     * @return
     */
   public static Object mthsnc(Object start,Object end,Object tobStr,String condition,JexlContext jc){
    int startIndex=0;
    int endIndex=0;    	
   	if(!"start".equals(start.toString())){   
   		try{
   			startIndex=Integer.parseInt(start.toString())-1;  
   		}catch(NumberFormatException e){
   			startIndex=(Integer) invokeParam(jc,start.toString(),0)-1;
   		}   		
   	}   	
   	if(!"end".equals(end.toString())){
   		endIndex=Integer.parseInt(end.toString())-1;    		   		
   	}     	
   	int tob;    
   	try{
   		    tob=Integer.parseInt(tobStr.toString())-1;  
		}catch(NumberFormatException e){
			tob=(Integer) invokeParam(jc,tobStr.toString(),0)-1;
	}   
   	if(endIndex>tob&&tob>=0) endIndex=tob;
   	//下标处理结束
   	int result=endIndex-1;
   	for(int i=startIndex;i<=endIndex;i++){
		if("true".equals(invokeParam(jc,condition,i).toString())){
			result=i-startIndex;
			break;
		}    		
	}
	   return result;
   }
   /**
    * 满足条件最小月份
    * @param start
    * @param end
    * @param index
    * @param tobStr
    * @param condition
    * @param jc
    * @return
    */
   public static Object mthsncOps(Object start,Object end,Object tobStr,String condition,JexlContext jc){
	    int startIndex=0;
	    int endIndex=0;    	
	   	if(!"start".equals(start.toString())){   
	   		try{
	   			startIndex=Integer.parseInt(start.toString())-1;  
	   		}catch(NumberFormatException e){
	   			startIndex=(Integer) invokeParam(jc,start.toString(),0)-1;
	   		}   		
	   	}   	
	   	if(!"end".equals(end.toString())){
	   		endIndex=Integer.parseInt(end.toString())-1;    		   		
	   	}     	
	   	int tob;    
	   	try{
	   		    tob=Integer.parseInt(tobStr.toString())-1;  
			}catch(NumberFormatException e){
				tob=(Integer) invokeParam(jc,tobStr.toString(),0)-1;
		}   
	   	if(endIndex>tob&&tob>=0) endIndex=tob;
	   	//下标处理结束
	   	int result=endIndex-1;
	   	for(int i=startIndex;i<=endIndex;i++){
			if("true".equals(invokeParam(jc,condition,i).toString())){
				result=i-startIndex;
			}    		
		}
		   return result;
	   }
   /**
    * 趋势的延续期数
    * @param start
    * @param end
    * @param tobStr
    * @param condition
    * @param jc
    * @return
    */
   public static Object trend(Object start,Object end,Object tobStr,String condition,JexlContext jc){
	    int startIndex=0;
	    int endIndex=0;    	
	   	if(!"start".equals(start.toString())){
	   		startIndex=Integer.parseInt(start.toString())-1;   		
	   	}   	
	   	if(!"end".equals(end.toString())){
	   		endIndex=Integer.parseInt(end.toString())-1;    		   		
	   	}     	
	   	int tob;    
	   	try{
	   		    tob=Integer.parseInt(tobStr.toString())-1;  
			}catch(NumberFormatException e){
				tob=(Integer) invokeParam(jc,tobStr.toString(),0)-1;
		}   
	   	if(endIndex>tob&&tob>=0) endIndex=tob;
	   	//下标处理结束
	   int result=0;
	   for(int i=startIndex;i<=endIndex;i++){
		   if("true".equals(invokeParam(jc,condition,i).toString())){
				result++;
			}else{
				break;
			}
	   }
	   return result;
   }
    public static void main(String[] args){
    	HashMap m=new HashMap();
    	
    	m.put("zkvq7tVj", 4);
    	m.put("GP9l9J5o", 120);
    	/*Calendar c=Calendar.getInstance();
    	c.set(2000, 4, 15);
    	m.put("8YltNz9y", c.getTime());*/
    	List l=new ArrayList();
    	l.add(10);//1
    	l.add(12);
    	l.add(10.22);
    	l.add(14);
    	l.add(15);//5子公式 
    	m.put("tt2Zfalq", l);
    	m.put("rWtw5AyG", 6);//账龄
        //String mathStr="sqrt(#{rWtw5AyG},jc)";
    	//String mathStr="1][+][conse2mx(1,4,#{rWtw5AyG}::-::1,#{tt2Zfalq}(index)::&lt;::#{tt2Zfalq}(index+1),jc)";//预计输出3
    	//String mathStr="arrsum(1,3,#{tt2Zfalq})";
    	//String mathStr="max(1,6,#{tt2Zfalq},#{rWtw5AyG},jc)";
    	//String mathStr="min(1,6,#{tt2Zfalq},#{rWtw5AyG},jc)";
        //	String mathStr="avg(1,6,#{tt2Zfalq},#{rWtw5AyG},jc)";
    	//String mathStr="maxdein(1,6,#{tt2Zfalq}(index+1),#{tt2Zfalq}(index),#{rWtw5AyG},jc)";
    	List l2=new ArrayList();
    	l2.add(10);//1
    	l2.add(11);
    	l2.add(120);
    	l2.add(13);
    	l2.add(14);//5子公式 
    	l2.add(1100);//5子公式 
    	m.put("pD2717Xw", l2);    	

         //String mathStr="finarpt(1,6,#{tt2Zfalq},#{pD2717Xw},#{rWtw5AyG},jc)";
        // String mathStr="ratio(#{zkvq7tVj},#{GP9l9J5o},jc)";
     //    String mathStr="frqpct(1,5,#{rWtw5AyG},#{rWtw5AyG}::&gt;::0,#{pD2717Xw}(index)::&gt;::=::#{pD2717Xw}(index+1),1,1,jc)";
         //String mathStr="countup(1,6,#{rWtw5AyG},#{pD2717Xw}(index)::&gt;::8::0::0,jc)";
    	List amt=new ArrayList();    	
    	List den=new ArrayList();
    	List lim=new ArrayList();
    	//january
    	amt.add(600);
    	den.add(2);
    	lim.add(1500);    	
    	//feburary
    	amt.add(0);
    	den.add(0);
    	lim.add(1500);
    	//March
    	amt.add(500);
    	den.add(1);
    	lim.add(1500);
    	//April
    	amt.add(100);
    	den.add(1);
    	lim.add(1500);
    	//May
    	amt.add(0);
    	den.add(0);
    	lim.add(1500);
    	//June
    	amt.add(0);
    	den.add(0);
    	lim.add(1500);
    	
    	m.put("zVXzzhGr", amt);
    	m.put("ZYghQLGO", den);
    	m.put("6hj0uswH", lim);
       //  String mathStr="eachrpt(1,6,#{rWtw5AyG},#{zVXzzhGr},#{ZYghQLGO},#{6hj0uswH},jc)";
    	List yq=new ArrayList();
    	yq.add(0);
    	m.put("XVMZ5Cp1", yq);
         //String mathStr="mthsncOps(#{XVMZ5Cp1}(index)::+::1,12,#{rWtw5AyG},#{pD2717Xw}(index)::&gt;::1::0::0,jc)";
        // String mathStr="trend(1,12,#{rWtw5AyG},#{pD2717Xw}(index)::&lt;::#{pD2717Xw}(index+1),jc)";

    	//
    	m.put("UqqiutLx", 10);
    	//String mathStr="power(#{UqqiutLx},#{rWtw5AyG}::+::1,jc)";
    //	String mathStr="log(3,9,jc)";
    	//String mathStr="ln(#{rWtw5AyG},jc)";
    	//String mathStr="exp(#{rWtw5AyG}::+::1,jc)";
    	m.put("RdZCQeYd", 2);
    	m.put("5jyyqO1Y", 4);
    	String mathStr="countup(1,1,#{RdZCQeYd}::-::1,#{5jyyqO1Y}::&gt;::3)][+][ln(1::2::+::#{5jyyqO1Y})";
    	CopyOfMathHelper.invokeMath(m,  mathStr);
    }

}
